package br.com.assinchronus.negocio;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import br.com.assinchronus.ai.Arvore;
import br.com.assinchronus.componentes.Casa;
import br.com.assinchronus.componentes.Dama;
import br.com.assinchronus.componentes.Peao;
import br.com.assinchronus.componentes.Pecas;
import br.com.assinchronus.util.RegraUtil;

public class RegraAI {

	private RegraGeral rg = new RegraGeral();
	private RegraPeao rp = new RegraPeao();
	private RegraDama rd = new RegraDama();
	private int[] vpos = { 0, 4, 4, 4, 4, 4, 3, 3, 3, 0, 3, 2, 2, 4, 4, 2, 1, 3, 0, 3, 1, 2, 4, 4, 2, 2, 3, 0, 3, 3, 3, 4, 4, 4, 4, 4 };
	private Map<Casa, List<Casa>> verificaObrigatoria;
	private Arvore root;
	private int melhorvalor;

	public Casa[] jogar(Casa[] tab, int nivel) {
		root = new Arvore(tab);
		montarArvore(root, nivel);
		Casa[] t = jogadaMax(root.getArvores());
		return t;
	}

	private Casa[] jogadaMax(List<Arvore> filhos) {
		int valor = 32000;
		ArrayList<Arvore> no = new ArrayList<Arvore>();
		for (Arvore node : filhos) {
			if (node.getValor() < valor) {
				valor = node.getValor();
			}
		}
		for (Arvore node : filhos) {
			if (node.getValor() == valor) {
				no.add(node);
			}
		}

		return no.get((int) Math.random() * no.size()).getTabuleiro();
	}

	protected void montarArvore(Arvore node, int nivel) {
		melhorvalor = 0;
		List<Arvore> filho = new ArrayList<Arvore>();
		verificaObrigatoria = rg.verificaObrigatoria(node.getTabuleiro(), nivel % 2 == 0 ? Pecas.PRETA : Pecas.BRANCA);
		if (nivel != 0) {
			filho = gerarFilho(node.getTabuleiro(), nivel % 2 == 0 ? Pecas.PRETA : Pecas.BRANCA, nivel);
			node.setArvores(filho);
			for (Arvore ar : node.getArvores()) {
				montarArvore(ar, nivel - 1);
				ar.setValor(melhorvalor);
			}
			if (nivel == 1) {
				for (Arvore no : node.getArvores()) {
					no.setValor(minmax(no.getTabuleiro()));
				}
			}
			if (nivel % 2 == 1) {
				for (Arvore no : node.getArvores()) {
					if (no.getValor() < melhorvalor) {
						melhorvalor = no.getValor();
					}
				}
			} else {
				for (Arvore no : node.getArvores()) {
					if (no.getValor() > melhorvalor) {
						melhorvalor = no.getValor();
					}
				}
			}
		}
	}

	private int minmax(Casa[] tab) {
		int valorB = 0;
		int valorP = 0;

		for (int i = 0; i < 36; i++) {
			if (i % 9 == 0 || tab[i].getPeca() == null) {
				continue;
			} else {
				if (tab[i].getPeca() instanceof Peao) {
					if (tab[i].getPeca().getCor() == Pecas.BRANCA) {
						if (i >= 28 && i <= 31) {
							valorB += vpos[i] * 7;
						} else {
							valorB += vpos[i] * 5;
						}
					} else {
						if (i >= 5 && i <= 8) {
							valorP += vpos[i] * 7;
						} else {
							valorP += vpos[i] * 5;
						}
					}
				} else {
					if (tab[i].getPeca() instanceof Dama && tab[i].getPeca().getCor() == Pecas.BRANCA) {
						valorB += vpos[i] * 10;
					} else if (tab[i].getPeca() instanceof Dama && tab[i].getPeca().getCor() == Pecas.BRANCA) {
						valorP += vpos[i] * 10;
					}
				}
			}
		}

		return valorP - valorB;
	}

	public List<Arvore> gerarFilho(Casa[] tab, int cor, int nivel) {

		List<Arvore> filho = new ArrayList<Arvore>();

		if (verificaObrigatoria.size() > 0) {
			for (Casa ob : verificaObrigatoria.keySet()) {
				List<Casa> listCasaObrigatorias = verificaObrigatoria.get(ob);

				for (Casa casa : listCasaObrigatorias) {
					Casa[] copy = RegraUtil.copy(tab);
					rg.atualizaTabuleiro(copy, copy[ob.getPosicao()], copy[casa.getPosicao()], JogadasEnum.COMER);
					List<Casa[]> listaSequencia = null;

					if (copy[casa.getPosicao()].getPeca() instanceof Peao) {
						listaSequencia = verificaSequenciaPeaoIA(copy, copy[casa.getPosicao()]);
					} else {
						listaSequencia = verificaSequenciaDamaIA(copy, copy[casa.getPosicao()]);
					}

					for (Casa[] tabSequencia : listaSequencia) {
						Arvore no = new Arvore(tabSequencia);
						filho.add(no);
					}
				}
			}
		} else {
			for (int i = 1; i < 36; i++) {
				if (i % 9 == 0 || (tab[i].getPeca() == null || tab[i].getPeca().getCor() != cor)) {
					continue;
				}
				if (tab[i].getPeca() instanceof Peao) {
					if (tab[i].getPeca().getCor() == Pecas.PRETA) {
						montarArvoreMoverPeao(tab, filho, i, -5);
						montarArvoreMoverPeao(tab, filho, i, -4);
					} else {
						montarArvoreMoverPeao(tab, filho, i, 5);
						montarArvoreMoverPeao(tab, filho, i, 4);
					}
				} else {
					montarArvoreMoverDamaNorte(tab, filho, i, 5);
					montarArvoreMoverDamaNorte(tab, filho, i, 4);
					montarArvoreMoverDamaSul(tab, filho, i, -4);
					montarArvoreMoverDamaSul(tab, filho, i, -5);
				}
			}
		}

		return filho;
	}

	protected List<Casa[]> verificaSequenciaPeaoIA(Casa[] copy, Casa casaInicial) {
		List<Casa[]> listaSequencia = new ArrayList<Casa[]>();
		List<Casa> casasFinais = rp.verificaSequencia(casaInicial, copy);
		if (casasFinais.size() > 0) {
			for (Casa casaFinal : casasFinais) {
				Casa[] clone = RegraUtil.copy(copy);
				rg.atualizaTabuleiro(clone, clone[casaInicial.getPosicao()], clone[casaFinal.getPosicao()], JogadasEnum.COMER);
				List<Casa[]> verificaSequenciaPeaoIA = verificaSequenciaPeaoIA(clone, clone[casaFinal.getPosicao()]);
				listaSequencia.addAll(verificaSequenciaPeaoIA);
			}
		} else {
			listaSequencia.add(copy);
		}
		return listaSequencia;
	}

	protected List<Casa[]> verificaSequenciaDamaIA(Casa[] copy, Casa casaInicial) {
		List<Casa[]> listaSequencia = new ArrayList<Casa[]>();
		List<Casa> casasFinais = rd.verificaSequencia(casaInicial, copy);
		if (casasFinais.size() > 0) {
			for (Casa casaFinal : casasFinais) {
				Casa[] clone = RegraUtil.copy(copy);
				rg.atualizaTabuleiro(clone, clone[casaInicial.getPosicao()], clone[casaFinal.getPosicao()], JogadasEnum.COMER);
				List<Casa[]> verificaSequenciaDamaIA = verificaSequenciaDamaIA(clone, clone[casaFinal.getPosicao()]);
				listaSequencia.addAll(verificaSequenciaDamaIA);
			}
		} else {
			listaSequencia.add(copy);
		}
		return listaSequencia;
	}

	private void montarArvoreMoverPeao(Casa[] tab, List<Arvore> arvore, int i, int pos) {
		if ((i + pos) > 0 && (i + pos) < 37 && (i + pos) % 9 != 0) {
			montarArvoreMover(tab, arvore, i, i + pos);
		}
	}

	private void montarArvoreMoverDamaNorte(Casa[] tab, List<Arvore> arvore, int i, int pos) {
		for (int j = i + pos; j < 36; j += pos) {
			if (j % 9 == 0) {
				break;
			}
			montarArvoreMover(tab, arvore, i, j);
		}
	}

	private void montarArvoreMoverDamaSul(Casa[] tab, List<Arvore> arvore, int i, int pos) {
		for (int j = i + pos; j > 0; j += pos) {
			if (j % 9 == 0) {
				break;
			}
			montarArvoreMover(tab, arvore, i, j);
		}
	}

	private void montarArvoreMover(Casa[] tab, List<Arvore> arvore, int i, int pos) {
		Casa[] tabAI = RegraUtil.copy(tab);
		Casa casaAtual = tabAI[i];
		if (tabAI[pos].getPeca() == null) {
			rg.verificaJogada(tabAI, casaAtual, tabAI[pos], false);
			if (tabAI[i].getPeca() == null) {
				arvore.add(new Arvore(tabAI));
			}
		}
	}
}